/*
 * Copyright (C) 2007,2008  Jonathan Hendler
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 * 
 * The authors can be contacted at: 
 * @author Jonathan Hendler [jonathan DOT hendler AT google DOT com]
 * 
 * @license GPLv2
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "sqlite3.h"
#include "sqlite_helper.h"

/**
 * (c) 2007 Jonathan Hendler
 * 
 * 
 * //http://www.sqlite.org/datatype3.html
 * @todo check autocommit
 * 
 * */
int nymrl_sqlite_close(sqlite3 * db){
	return NYMRL_SQLITE_CLOSE(db);
}

inline void nymrl_sqlite_open(const char * dbname, sqlite3 ** new_db_){
	srand( (unsigned) time(NULL)*getpid());
	
	int result = sqlite3_enable_shared_cache(TRUE);
	if (result != SQLITE_OK ){
		ny_log_error("sqlite3_enable_shared_cache() FAILED %s/n",sqlite3_errmsg(*new_db_));
		nymrl_sqlite_close(*new_db_);
		return  ;
	}	
	
	int ret = NYMRL_SQLITE_OPEN(dbname, new_db_);
	if(ret){
		//failed
	//	ny_log_error();
		ny_log_error("OPEN %s FAILED %s/n",dbname,sqlite3_errmsg(*new_db_));
		nymrl_sqlite_close(*new_db_);
		return ;
	}
	
	result = sqlite3_threadsafe();
	if (!result){
		    ny_log_error("sqlite3_threadsafe() FAILED %s/n",sqlite3_errmsg(*new_db_));
			nymrl_sqlite_close(*new_db_);
			return  ;
	}
	//
	
	char * sql =  nymrl_sqlite_create_sql("PRAGMA default_cache_size = %d",NYMRL_SQLITE_CACHE_SIZE);
	nymrl_sqlite_exec(*new_db_,sql);

	return;
}

void nymrl_sqlite_print_debug_info(sqlite3 *db,const char * sql){
	_nymrl_sqlite_print_debug_info(db,"PRAGMA default_cache_size");
	_nymrl_sqlite_print_debug_info(db,"PRAGMA fullfsync");
	_nymrl_sqlite_print_debug_info(db,"PRAGMA synchronous");
	_nymrl_sqlite_print_debug_info(db,"PRAGMA locking_mode");
	_nymrl_sqlite_print_debug_info(db,"PRAGMA integrity_check");
	_nymrl_sqlite_print_debug_info(db,"PRAGMA vdbe_listing = ON ");
	_nymrl_sqlite_print_debug_info(db,sql);
}

inline void _nymrl_sqlite_print_debug_info(sqlite3 *db, const char * sql){
	printf("\n\t%s=\t",sql);
	char * _sql =  nymrl_sqlite_create_sql(sql);
	nymrl_sqlite_get_results(1,db,_sql);
}


char * nymrl_sqlite_create_sql(const char * sql,...){
	char *tmp;
	va_list ap;
	va_start(ap,sql);
	tmp = sqlite3_vmprintf(sql,ap);
	va_end(ap);
	return tmp;
}

//open transaction
//close transaction

//transactional insert/update/delete
/*
 * non transactional insert/update/delete
 * usage: 
 * 	int cid 1
 *  char * sql = "insert %i,'%q'"
 *  nymrl_sqlite_exec(db,sql, cid,"value"
 */
inline int nymrl_sqlite_exec(sqlite3 *db,char * sql){
	if (strlen(sql) == 0) return FALSE;
	
	char *err;
	int rc = sqlite3_exec(db,sql,NULL,NULL,&err);
	if (rc != SQLITE_OK){
		if(err != NULL){
			ny_log_error("nymrl_sqlite_exec() err %i: %s\n%s\n",rc,err,sql);
			sqlite3_free(err);
			sqlite3_free(sql);
			return rc;
		}
	}
	sqlite3_free(sql);
	return rc;
}


inline int nymrl_sqlite_exec_changes(sqlite3 *db,char * sql,char ** err){
	if (strlen(sql) == 0) return FALSE;
	int rc = sqlite3_exec(db,sql,NULL,NULL,err);
	if (rc != SQLITE_OK){
		if(*err != NULL){
			sqlite3_free(sql);
			return rc;
		}
	}
	sqlite3_free(sql);
	return sqlite3_changes(db);
}

/**
 * returns auto increment row id
 * */
sqlite_int64 nymrl_sqlite_insert_and_get_id(sqlite3 *db, char * sql){
	 nymrl_sqlite_exec(db,sql);
	 return sqlite3_last_insert_rowid(db);
	 
}

void nymrl_print_result(char ** result,int nrows,int ncols){
	int i,j;
	for(i=0;i< nrows;i++){
		for (j=0;j<ncols;j++){
			fprintf(stdout,"\t%s",result[(i+1)*ncols+j]);
		}
		fprintf(stdout,"\n");
	}
	
	sqlite3_free_table(result);
}

//char * nymrl_sqlite_copy_single_value( void * item,int count, int unit_size){
//	//register int i;
//	//strcpy();
//	static char * return_value;
//	//char * temp = return_value;
//	//char * temp2 = item;
//	//sprintf(return_value,"%s" ,(char *) item);
//	
//	
//	//padding
//	//temp[i++] = '\0';
//	//sqlite3_result_text()
//	 
//	return return_value;
//}


inline char * nymrl_sqlite_get_single_value(sqlite3 *db , char * sql ){
	
//	NYMRL_SQLITE_STEP_ITERATE(column_value,db,sql,j) 
//		column_value =  sqlite3_column_text(stmt, j);
//	    //fprintf(stdout, "\tresult '%s' ", );
//		if (strlen(column_value) >0) break;
//	NYMRL_SQLITE_STEP_ITERATE_CLOSE;
//	
//	return  ((column_value) && strlen(column_value) > 0) ? column_value : &("");
	
	
	NYMRL_SQLITE_GET_RESULTS;
	int  index_pos;
	size_t size;
	static char * return_value = "";
	char * temp;
	 
	if (nrows>0){
		NYMRL_RESULT_ITERATOR(result,ncols,nrows,i,j)
				index_pos = (i+1)*ncols+j;
				temp = result[index_pos];
				//the +1 is needed to include the \0 file
				size = strlen((char *)temp)+1;
				//printf("\n size %d, value %s",(int)size,temp);
				if ((size >1)){
					return_value = (char *) malloc(size*sizeof(char));
					strncpy(return_value,(char *) temp,size);
					//return_value = (char*) nymrl_sqlite_copy_single_value(temp,size,sizeof(char));
				}
				if (strlen(return_value)>0) break;
			}
		}
	}  else{
		return_value = "";
	}
	
	NYMRL_SQLITE_RESULT_CLEANUP;
	//return return_value;
	return  return_value;
}

/**
 * calling functions must call //sqlite3_free_table(result)
 * */
inline char ** nymrl_sqlite_get_results(int print ,sqlite3 *db, char * sql){
	NYMRL_SQLITE_GET_RESULTS;
	
	if (print == 1){
		nymrl_print_result(result,nrows,ncols);
		sqlite3_free(sql);
		return NULL;
	} else {
		return result;
	}
}

/////////////////////////////////
// General convienience fucntions
int nymrl_sqlite_drop_table(sqlite3 *db,  char * table_name){
	const char * sql = "DROP TABLE IF EXISTS %s";
	char * final_sql = nymrl_sqlite_create_sql(sql,table_name);
	return nymrl_sqlite_exec(db,final_sql);
}




//get results 

 
